{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# RandomForest 文本分类训练流程\n",
        "\n",
        "本notebook提供完整的RandomForest训练流程，支持11分类文本分类任务。\n",
        "\n",
        "## 数据集信息\n",
        "- **总样本数**: 20,000\n",
        "- **分类任务**: 11分类（1个不违规 + 10个违规子类）\n",
        "- **数据格式**: JSONL格式，包含text、label、subject三个字段\n",
        "- **特征提取**: TF-IDF + 字符级n-gram\n",
        "- **数据划分**: 8:1:1 (train:test:dev)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 1. 环境准备和导入\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "当前工作目录: d:\\jp_workplace\\TextClassify\n",
            "Python路径已添加: d:\\jp_workplace\\TextClassify\\src\n",
            "开始时间: 2025-09-18 08:58:26\n"
          ]
        }
      ],
      "source": [
        "import os\n",
        "import sys\n",
        "import json\n",
        "import time\n",
        "import pandas as pd\n",
        "import numpy as np\n",
        "from datetime import datetime\n",
        "\n",
        "# 添加src目录到Python路径，避免路径问题\n",
        "sys.path.append(os.path.join(os.getcwd(), 'src'))\n",
        "\n",
        "print(f\"当前工作目录: {os.getcwd()}\")\n",
        "print(f\"src路径已添加到工作目录: {os.path.join(os.getcwd(), 'src')}\")\n",
        "print(f\"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 2. 配置文件加载和验证\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "✅ 模块导入成功\n"
          ]
        }
      ],
      "source": [
        "# 导入训练模块\n",
        "from training_operation import TrainingOperation, create_training_operation\n",
        "from models import create_model\n",
        "\n",
        "print(\"✅ 模块导入成功\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "📁 配置文件加载成功\n",
            "配置节: ['random_state', 'models', 'data', 'label_mapping', 'feature_extraction', 'training']\n",
            "\n",
            "RandomForest配置: {'n_estimators': 100, 'max_depth': 10, 'min_samples_split': 2, 'min_samples_leaf': 1, 'n_jobs': -1}\n",
            "\n",
            "标签映射数量: 11个\n",
            "标签映射:\n",
            "  0: 不违规_不违规\n",
            "  1: 违规_偏见歧视\n",
            "  2: 违规_淫秽色情\n",
            "  3: 违规_财产隐私\n",
            "  4: 违规_心理健康\n",
            "  5: 违规_违法犯罪\n",
            "  6: 违规_脏话侮辱\n",
            "  7: 违规_身体伤害\n",
            "  8: 违规_政治错误\n",
            "  9: 违规_道德伦理\n",
            "  10: 违规_变体词\n"
          ]
        }
      ],
      "source": [
        "# 加载配置文件\n",
        "config = TrainingOperation.load_config_operator('config/models.yaml')\n",
        "\n",
        "print(\"📁 配置文件加载成功\")\n",
        "print(f\"配置节: {list(config.keys())}\")\n",
        "\n",
        "# 显示RandomForest配置\n",
        "rf_config = config.get('models', {}).get('random_forest', {})\n",
        "print(f\"\\nRandomForest配置: {rf_config}\")\n",
        "\n",
        "# 显示标签映射，仅机器学习。除非效果不好，否则深度学习不使用\n",
        "label_mapping = config.get('label_mapping', {})\n",
        "print(f\"\\n标签映射数量: {len(label_mapping)}个\")\n",
        "print(\"标签映射:\")\n",
        "for label, idx in label_mapping.items():\n",
        "    print(f\"  {idx}: {label}\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔍 配置验证结果: ✅ 通过\n",
            "问题/警告 (1个):\n",
            "  1. RandomForest缺少random_state参数，将使用默认值\n"
          ]
        }
      ],
      "source": [
        "# 配置验证\n",
        "is_valid, issues = TrainingOperation.validate_config_operator(config)\n",
        "\n",
        "print(f\"🔍 配置验证结果: {'✅ 通过' if is_valid else '❌ 失败'}\")\n",
        "\n",
        "if issues:\n",
        "    print(f\"问题/警告 ({len(issues)}个):\")\n",
        "    for i, issue in enumerate(issues, 1):\n",
        "        print(f\"  {i}. {issue}\")\n",
        "else:\n",
        "    print(\"✅ 无配置问题\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 3. 数据集分析和预览\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "✅ 数据文件存在: data/test.jsonl\n",
            "文件大小: 5.41 MB\n"
          ]
        }
      ],
      "source": [
        "# 检查数据文件\n",
        "data_path = 'data/test.jsonl'\n",
        "\n",
        "if os.path.exists(data_path):\n",
        "    print(f\"✅ 数据文件存在: {data_path}\")\n",
        "    \n",
        "    # 获取文件大小\n",
        "    file_size = os.path.getsize(data_path) / (1024 * 1024)  # MB\n",
        "    print(f\"文件大小: {file_size:.2f} MB\")\n",
        "else:\n",
        "    print(f\"❌ 数据文件不存在: {data_path}\")\n",
        "    raise FileNotFoundError(f\"请确保数据文件存在: {data_path}\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            " 加载数据进行分析...\n",
            "✅ 模型配置加载成功\n",
            "✅ 路径配置加载成功\n",
            "数据加载完成: (20000, 3)\n",
            "\n",
            " 数据基本信息:\n",
            "  总样本数: 20000\n",
            "  列名: ['text', 'label', 'subject']\n",
            "  缺失值: {'text': 0, 'label': 0, 'subject': 0}\n",
            "\n",
            " 数据预览 (前5行):\n"
          ]
        },
        {
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>text</th>\n",
              "      <th>label</th>\n",
              "      <th>subject</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>比起外国人的文化，我们中国的文化才是真正的优秀和高尚。</td>\n",
              "      <td>违规</td>\n",
              "      <td>偏见歧视</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>非洲和中国被长期贬低，被认为是不发达的，但这些国家和文化都有它们独特的价值和文化，这样的认知...</td>\n",
              "      <td>违规</td>\n",
              "      <td>偏见歧视</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>尼古洛巴托总统国际机场（，），之前称科摩罗国际机场（），机场位于东帝汶帝力。因尼古·洛巴托在...</td>\n",
              "      <td>不违规</td>\n",
              "      <td>不违规</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>#阿黑颜 #啊嘿颜 #崩坏脸 #高潮脸 #重口  #翻白眼舌头 #口腔 #舌头 #扁桃体 #...</td>\n",
              "      <td>违规</td>\n",
              "      <td>淫秽色情</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>所以文学您说的不确定性、未知性,其实特别能培养人的情商”根据前面的段落，以下是否是真的“文学...</td>\n",
              "      <td>不违规</td>\n",
              "      <td>不违规</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "                                                text label subject\n",
              "0                        比起外国人的文化，我们中国的文化才是真正的优秀和高尚。    违规    偏见歧视\n",
              "1  非洲和中国被长期贬低，被认为是不发达的，但这些国家和文化都有它们独特的价值和文化，这样的认知...    违规    偏见歧视\n",
              "2  尼古洛巴托总统国际机场（，），之前称科摩罗国际机场（），机场位于东帝汶帝力。因尼古·洛巴托在...   不违规     不违规\n",
              "3  #阿黑颜 #啊嘿颜 #崩坏脸 #高潮脸 #重口  #翻白眼舌头 #口腔 #舌头 #扁桃体 #...    违规    淫秽色情\n",
              "4  所以文学您说的不确定性、未知性,其实特别能培养人的情商”根据前面的段落，以下是否是真的“文学...   不违规     不违规"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# 加载和分析数据\n",
        "print(\" 加载数据进行分析...\")\n",
        "\n",
        "# 创建模型实例用于数据处理\n",
        "rf_model = create_model('random_forest', config)\n",
        "\n",
        "# 加载数据\n",
        "df = rf_model._load_jsonl_data(data_path)\n",
        "print(f\"数据加载完成: {df.shape}\")\n",
        "\n",
        "# 显示数据基本信息\n",
        "print(f\"\\n 数据基本信息:\")\n",
        "print(f\"  总样本数: {len(df)}\")\n",
        "print(f\"  列名: {list(df.columns)}\")\n",
        "print(f\"  缺失值: {df.isnull().sum().to_dict()}\")\n",
        "\n",
        "# 数据预览\n",
        "print(\"\\n 数据预览 (前5行):\")\n",
        "display(df.head())\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 4. 开始训练过程\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-09-18 08:58:29,160 - TrainingOperation - INFO - 🚀 开始训练单个模型: random_forest\n",
            "2025-09-18 08:58:29,165 - TrainingOperation - INFO - 🔄 发现已有模型，进行增量训练: models/random_forest_model.pkl\n",
            "2025-09-18 08:58:29,171 - TrainingOperation - INFO - 🚀 开始训练RandomForest模型\n",
            "2025-09-18 08:58:29,174 - TrainingOperation - INFO - 模型配置: {'n_estimators': 100, 'max_depth': 10, 'min_samples_split': 2, 'min_samples_leaf': 1, 'n_jobs': -1}\n",
            "2025-09-18 08:58:29,180 - TrainingOperation - INFO - 开始时间: 2025-09-18 08:58:29\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🚀 创建训练编排器...\n",
            "✅ 训练编排器创建成功\n",
            "模型保存路径: models/random_forest_model.pkl\n",
            "\n",
            " 开始RandomForest训练...\n",
            "============================================================\n",
            "✅ 模型配置加载成功\n",
            "✅ 路径配置加载成功\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Training RandomForest: 100%|██████████| 10/10 [02:12<00:00, 13.28s/%]\n",
            "2025-09-18 09:00:54,082 - TrainingOperation - INFO - 结果已保存到: results\\random_forest_incremental_results.json\n",
            "2025-09-18 09:00:54,082 - TrainingOperation - INFO - ✅ RandomForest训练完成\n",
            "2025-09-18 09:00:54,084 - TrainingOperation - INFO - 训练用时: 144.85秒\n",
            "2025-09-18 09:00:54,085 - TrainingOperation - INFO - 最终测试集性能:\n",
            "2025-09-18 09:00:54,085 - TrainingOperation - INFO -   准确率: 0.5995\n",
            "2025-09-18 09:00:54,085 - TrainingOperation - INFO -   精确率(macro): 0.7956\n",
            "2025-09-18 09:00:54,087 - TrainingOperation - INFO -   召回率(macro): 0.2718\n",
            "2025-09-18 09:00:54,087 - TrainingOperation - INFO -   F1分数(macro): 0.3139\n",
            "2025-09-18 09:00:54,088 - TrainingOperation - INFO - 结束时间: 2025-09-18 09:00:54\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "============================================================\n",
            "🎉 训练完成！\n",
            "总训练时间: 144.94秒\n"
          ]
        }
      ],
      "source": [
        "# 创建训练编排器\n",
        "print(\"🚀 创建训练编排器...\")\n",
        "\n",
        "trainer = create_training_operation('config/models.yaml', 'config/paths.yaml')\n",
        "\n",
        "print(\"✅ 训练编排器创建成功\")\n",
        "print(f\"模型保存路径: {trainer.paths.get('models', {}).get('random_forest')}\")\n",
        "\n",
        "# 开始训练\n",
        "print(\"\\n 开始RandomForest训练...\")\n",
        "print(\"=\" * 60)\n",
        "\n",
        "start_time = time.time()\n",
        "\n",
        "try:\n",
        "    # 执行训练\n",
        "    training_results = trainer.train_single_model_operator('random_forest', data_path)\n",
        "    \n",
        "    training_time = time.time() - start_time\n",
        "    \n",
        "    print(\"\\n\" + \"=\" * 60)\n",
        "    print(\"🎉 训练完成！\")\n",
        "    print(f\"总训练时间: {training_time:.2f}秒\")\n",
        "    \n",
        "except Exception as e:\n",
        "    print(f\"❌ 训练失败: {str(e)}\")\n",
        "    import traceback\n",
        "    traceback.print_exc()\n",
        "    raise\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 5. 训练结果分析\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "📊 训练结果分析:\n",
            "==================================================\n",
            "模型类型: RandomForest\n",
            "训练时间: 144.85秒\n",
            "特征维度: 10000\n",
            "训练样本数: 15999\n",
            "测试样本数: 2000\n",
            "验证样本数: 2001\n",
            "\n",
            "🎯 测试集性能:\n",
            "  准确率: 0.5995\n",
            "  精确率(macro): 0.7956\n",
            "  召回率(macro): 0.2718\n",
            "  F1分数(macro): 0.3139\n",
            "  F1分数(micro): 0.5995\n",
            "  F1分数(weighted): 0.0000\n"
          ]
        }
      ],
      "source": [
        "# 显示训练结果\n",
        "print(\"📊 训练结果分析:\")\n",
        "print(\"=\" * 50)\n",
        "\n",
        "# 基本信息\n",
        "print(f\"模型类型: {training_results.get('model_name', 'N/A')}\")\n",
        "print(f\"训练时间: {training_results.get('training_time', 0):.2f}秒\")\n",
        "print(f\"特征维度: {training_results.get('feature_dim', 'N/A')}\")\n",
        "print(f\"训练样本数: {training_results.get('train_samples', 'N/A')}\")\n",
        "print(f\"测试样本数: {training_results.get('test_samples', 'N/A')}\")\n",
        "print(f\"验证样本数: {training_results.get('dev_samples', 'N/A')}\")\n",
        "\n",
        "# 性能指标\n",
        "test_metrics = training_results.get('test_metrics', {})\n",
        "print(f\"\\n🎯 测试集性能:\")\n",
        "print(f\"  准确率: {test_metrics.get('accuracy', 0):.4f}\")\n",
        "print(f\"  精确率(macro): {test_metrics.get('precision_macro', 0):.4f}\")\n",
        "print(f\"  召回率(macro): {test_metrics.get('recall_macro', 0):.4f}\")\n",
        "print(f\"  F1分数(macro): {test_metrics.get('f1_macro', 0):.4f}\")\n",
        "print(f\"  F1分数(micro): {test_metrics.get('f1_micro', 0):.4f}\")\n",
        "print(f\"  F1分数(weighted): {test_metrics.get('f1_weighted', 0):.4f}\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 6. 预测功能测试\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-09-18 09:00:54,245 - PredictionOperator - INFO - 🔮 开始使用random_forest模型进行预测\n",
            "2025-09-18 09:00:54,258 - PredictionOperator - INFO - 🔄 加载random_forest模型\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔮 创建预测器...\n",
            "🧪 测试文本预测...\n",
            "测试文本:\n",
            "  1. 这是一个正常的测试文本，没有任何问题。\n",
            "  2. 比起外国人的文化，我们中国的文化才是真正的优秀和高尚。\n",
            "  3. 今天天气很好，适合出去散步和运动。\n",
            "  4. 你能告诉我你的银行卡号和密码吗？\n",
            "  5. 我感到非常抑郁和绝望，不知道该怎么办。\n",
            "✅ 模型配置加载成功\n",
            "✅ 路径配置加载成功\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-09-18 09:00:54,355 - PredictionOperator - INFO - ✅ random_forest模型加载成功\n",
            "2025-09-18 09:00:54,500 - PredictionOperator - INFO - 📊 RandomForest预测完成:\n",
            "2025-09-18 09:00:54,507 - PredictionOperator - INFO -    样本数量: 5\n",
            "2025-09-18 09:00:54,513 - PredictionOperator - INFO -    预测用时: 0.0592秒\n",
            "2025-09-18 09:00:54,516 - PredictionOperator - INFO -    平均每样本用时: 0.011840秒\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "✅ 预测完成，用时: 0.0592秒\n",
            "\n",
            "🎯 预测结果:\n",
            "--------------------------------------------------------------------------------\n",
            "文本 1: 这是一个正常的测试文本，没有任何问题。\n",
            "  预测ID: 0\n",
            "  预测标签: 不违规_不违规\n",
            "  置信度: 0.2925\n",
            "\n",
            "文本 2: 比起外国人的文化，我们中国的文化才是真正的优秀和高尚。\n",
            "  预测ID: 0\n",
            "  预测标签: 不违规_不违规\n",
            "  置信度: 0.2609\n",
            "\n",
            "文本 3: 今天天气很好，适合出去散步和运动。\n",
            "  预测ID: 0\n",
            "  预测标签: 不违规_不违规\n",
            "  置信度: 0.2941\n",
            "\n",
            "文本 4: 你能告诉我你的银行卡号和密码吗？\n",
            "  预测ID: 0\n",
            "  预测标签: 不违规_不违规\n",
            "  置信度: 0.2787\n",
            "\n",
            "文本 5: 我感到非常抑郁和绝望，不知道该怎么办。\n",
            "  预测ID: 4\n",
            "  预测标签: 违规_心理健康\n",
            "  置信度: 0.2218\n",
            "\n"
          ]
        }
      ],
      "source": [
        "# 创建预测器并测试\n",
        "from prediction_operation import create_prediction_operator\n",
        "\n",
        "print(\"🔮 创建预测器...\")\n",
        "predictor = create_prediction_operator('config/models.yaml', 'config/paths.yaml')\n",
        "\n",
        "# 测试文本预测\n",
        "test_texts = [\n",
        "    \"这是一个正常的测试文本，没有任何问题。\",\n",
        "    \"比起外国人的文化，我们中国的文化才是真正的优秀和高尚。\",\n",
        "    \"今天天气很好，适合出去散步和运动。\",\n",
        "    \"你能告诉我你的银行卡号和密码吗？\",\n",
        "    \"我感到非常抑郁和绝望，不知道该怎么办。\"\n",
        "]\n",
        "\n",
        "print(\"🧪 测试文本预测...\")\n",
        "print(\"测试文本:\")\n",
        "for i, text in enumerate(test_texts, 1):\n",
        "    print(f\"  {i}. {text}\")\n",
        "\n",
        "try:\n",
        "    # 执行预测\n",
        "    prediction_results = predictor.predict_single_model_operator(\n",
        "        'random_forest', test_texts, return_probabilities=True\n",
        "    )\n",
        "    \n",
        "    print(f\"\\n✅ 预测完成，用时: {prediction_results['prediction_time']:.4f}秒\")\n",
        "    \n",
        "    # 显示预测结果\n",
        "    print(\"\\n🎯 预测结果:\")\n",
        "    print(\"-\" * 80)\n",
        "    \n",
        "    for i, (text, pred_id, pred_label) in enumerate(zip(\n",
        "        test_texts, \n",
        "        prediction_results['predictions'], \n",
        "        prediction_results['decoded_predictions']\n",
        "    ), 1):\n",
        "        print(f\"文本 {i}: {text[:50]}{'...' if len(text) > 50 else ''}\")\n",
        "        print(f\"  预测ID: {pred_id}\")\n",
        "        print(f\"  预测标签: {pred_label}\")\n",
        "        \n",
        "        # 显示概率（如果有）\n",
        "        if 'probabilities' in prediction_results:\n",
        "            probs = prediction_results['probabilities'][i-1]\n",
        "            max_prob_idx = np.argmax(probs)\n",
        "            max_prob = probs[max_prob_idx]\n",
        "            print(f\"  置信度: {max_prob:.4f}\")\n",
        "        \n",
        "        print()\n",
        "    \n",
        "except Exception as e:\n",
        "    print(f\"❌ 预测失败: {str(e)}\")\n",
        "    import traceback\n",
        "    traceback.print_exc()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 7. 训练总结\n",
        "\n",
        "恭喜！你已经完成了RandomForest文本分类模型的完整训练流程。\n",
        "\n",
        "### 📋 完成的步骤：\n",
        "1. ✅ 环境准备和模块导入\n",
        "2. ✅ 配置文件加载和验证\n",
        "3. ✅ 数据集分析和预览\n",
        "4. ✅ 模型训练过程\n",
        "5. ✅ 训练结果分析\n",
        "6. ✅ 预测功能测试\n",
        "\n",
        "### 🎯 下一步建议：\n",
        "\n",
        "#### 模型优化：\n",
        "- 封装判断过拟合的方法，增加评价过拟合的指标\n",
        "- **如果过拟合**: 减少 `n_estimators`，增加 `min_samples_split`\n",
        "- **如果欠拟合**: 增加 `n_estimators`，减少 `min_samples_split`\n",
        "- **特征优化**: 调整 `max_features` 和 `ngram_range`，加入停止词表\n",
        "\n",
        "#### 查看详细结果：\n",
        "- **分类报告**: 检查 `results/reports/` 目录\n",
        "- **可视化图表**: 检查 `results/plots/` 目录\n",
        "- **训练日志**: 检查 `logs/` 目录\n",
        "\n",
        "#### 模型使用：\n",
        "```python\n",
        "# 加载训练好的模型进行预测\n",
        "from prediction_operation import create_prediction_operator\n",
        "predictor = create_prediction_operator()\n",
        "results = predictor.predict_single_model_operator('random_forest', ['你的文本'])\n",
        "```\n",
        "\n",
        "#### 对比其他模型：\n",
        "可以继续实现SVM、FastText、TextCNN、BERT等其他模型进行性能对比。\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "nlp_base",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.18"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}
